3. Assignment 3: FIFO¶
The First-In-First-Out concept has been presented in the lecture a few times, but not in details.
In this assigment, we will implement a single clock FIFO, which means that read and write logic are driven by one clock.
You should at least complete the register Memory FIFO, the RAM Fifo can be skipped if you don’t have enough time, but you should read the assignment description to see the difference between a RAM or register FIFO.
3.1. Work Folder¶
Don’t forget to create a new workfolder called assignment3, you can copy-paste the previous testbench.
3.2. Register Memory FIFO¶
For the first variant, we will use a register memory, meaning you can just declare your memory as following:
reg [WIDTH-1:0] memory [DEPTH:0];
And access it like an array:
// write
memory[address] <= VALUE;
// read
value <= memory[address]
The design should be driven by the following interface:

Single clock and reset (async or sync reset as you wish)
Data width is a parameter
Memory depth is a parameter (for example make it 512 or 1024 entries)
Make sure the status signals have a proper reset, don’t reset the data.
- Write interface:
- data_in : the data to be written.
- shift_in : when asserted, write the data in the memory.
- Read interface:
- data_out : the actual available data.
- shift_out: when asserted, the next data_out is requested and available in the next clock cycle.
- Status Interface:
- full : when no more data should be “shifted in”.
- almost_full: when there is only one data entry left in the memory. You can make a parameter for this signal.
- empty: when no data is present to be “shifted out”.
- almost_empty: when there is only one data entry left in the memory. You can make a parameter for this signal.
- data_out always displays the actual available data, shift_out requests the next.
- It is different than a classical memory, you don’t request the data and wait for it. The data is ready and you ask for the next one, i.e mark
the current data as “consumed”.
The almostfull/empty signals are essential as they allow to know when the last data can be written, and the next cycle the memory wil be full.
Warning
read carefuly the description of data_out.
3.2.1. Designing by Unit Testing¶
Try to use the testbench to implement the module:
- Prepare the testbench
- Prepare the FIFO module with input/outputs, add it to the test bench, connect clock and reset
- Make a list of tests, from very simple to more complex, for example:
- write one word of data, empty should be 0
- read one word of data, empty should be 1
- Write the tests as comments inside the “initial” block:
- Add the code that drives the input/outputs of the fifo for the first test
- Try to check the result of the test and use the $error function to signal an incorrect result
- Run the simulation, it should fail if you used the $error check correctely
- Add the FIFO hw description until the simulation is not failing anymore
- Repeat for all the tests
- When implementing features, the testbench will always check the simple tests at the beginning, this way you know if you have added a bug while implementing a new feature
3.3. RAM Memory FIFO¶
The register based FIFO is not too complex, but we have seen that if the memory grows, the costs of a register memory in terms of Area and timing will be too high.
The solution is to replace the memory array by an SRAM Module.
3.3.1. RAM Block¶
For the UMC65 tehcnology, we have two RAM blocks:
- 64 bits x 1024 entries
- 32 bits x 512 entries
The RAM blocks are available in the design kit folder under:
- SIZE is 1024x64 or 512x32
- Verilog model: /var/autofs/cadence/umc-65/rams/SIZE/SJKA65_**SIZE**X1CM4/SJKA65_**SIZE**X1CM4.v
- Timing Library for synthesis: /var/autofs/cadence/umc-65/rams/SIZE/SJKA65_**SIZE**X1CM4/SJKA65_**SIZE**X1CM4_**CORNER**.lib
- LEF File for physcial placement: /var/autofs/cadence/umc-65/rams/SIZE/SJKA65_**SIZE**X1CM4/SJKA65_**SIZE**X1CM4.lef
- Datasheet: /var/autofs/cadence/umc-65/rams/SIZE/SJKA65_**SIZE**X1CM4/SJKA65_**SIZE**X1CM4.ds
To use the RAM, you just need to:
- Look at the verilog model
- Instantiate the module and connect the input/outputs
- Add the verilog model to the list of verilog files when starting the simulation
The RAM Model is a bit annoying to instantiate, because all the bits are presented as single inputs or outputs.
Question
How many clocks does the RAM have?
Question
Which Port would you choose to write and read data?
Hint
Search for the WEAN/WEAN and CSAN/CSBN signals, and determine which value combinate read or write from/to the memory.
Todo
Write a quick testbench to train using the module and see how data are written and read.
Warning
Add the -notimingchecks argument to the irun call to avoid timing checks and RAM model failing to work because of the ideal timing in the simulator.
3.3.2. Design Update¶
When replacing the register memory with the RAM block, you will see that you can’t just use the assignment operator, you have to set the input and outputs of the RAM.
Warning
Make a copy of the fifo module, and name it for example: fifo_ram
Question
Can you keep the parameterized width and depth? How would you handle different user WIDTH and DEPTH?
Question
How does the RAM usage affect the data delay in the design?
Warning
The specification of the FIFO cannot be changed
Question
Can you figure out a way to cope with the RAM addition?
Use the testbench unchanged to test the new fifo.